home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / graphics / jpeg2ps / jpeg2ps.c < prev    next >
C/C++ Source or Header  |  1999-12-06  |  13KB  |  418 lines

  1. /* --------------------------------------------------------------------
  2.  * jpeg2ps: convert JPEG files to compressed PostScript Level 2 EPS
  3.  *
  4.  * (C) 1994-1999 Thomas Merz 
  5.  *
  6.  * ------------------------------------------------------------------*/
  7.  
  8. #define VERSION        "V1.8"
  9.  
  10. #include <stdio.h>
  11. #include <time.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14.  
  15. #ifndef DOS
  16. #include <unistd.h>
  17. #endif
  18.  
  19. #ifdef DOS
  20. #include <dos.h>
  21. #include <io.h>
  22. #include <fcntl.h>
  23. #endif
  24.  
  25. /* try to identify Mac compilers */
  26. #if __POWERPC__ || __CFM68K__ || __MC68K_
  27. #define MAC
  28. #endif
  29.  
  30. #ifdef MAC
  31. #include "Main.h"        /* Required for DropUNIX */
  32. #endif
  33.  
  34. #include "psimage.h"
  35.  
  36. #if (defined(DOS) || defined (MAC))
  37. #define READMODE  "rb"           /* read JPEG files in binary mode */
  38. #define WRITEMODE "wb"           /* write (some) PS files in binary mode */
  39. #else
  40. #define READMODE  "r"
  41. #define WRITEMODE "w"           /* write (some) PS files in binary mode */
  42. #endif
  43.  
  44. int Margin         = 20;           /* safety margin */
  45. BOOL quiet    = FALSE;    /* suppress informational messages */
  46. BOOL autorotate = FALSE;    /* disable automatic rotation */
  47.  
  48. extern BOOL    AnalyzeJPEG P1(imagedata *, image);
  49. extern int    ASCII85Encode P2(FILE *, in, FILE *, out);
  50. extern void     ASCIIHexEncode P2(FILE *, in, FILE *, out);
  51.  
  52. #ifndef MAC
  53. extern char *optarg;
  54. extern int optind;
  55. #endif
  56.  
  57. #ifdef DOS
  58. extern int      getopt P3(int, nargc, char **, nargv, char *, ostr);
  59. #endif
  60.  
  61. #define BUFFERSIZE 1024
  62. static char buffer[BUFFERSIZE];
  63. static char *ColorSpaceNames[] = {"", "Gray", "", "RGB", "CMYK" };
  64.  
  65. /* Array of known page sizes including name, width, and height */
  66.  
  67. typedef struct { const char *name; int width; int height; } PageSize_s;
  68.  
  69. PageSize_s PageSizes[] = {
  70.     {"a0",    2380, 3368},
  71.     {"a1",    1684, 2380},
  72.     {"a2",    1190, 1684},
  73.     {"a3",    842, 1190},
  74.     {"a4",    595, 842},
  75.     {"a5",    421, 595},
  76.     {"a6",    297, 421},
  77.     {"b5",    501, 709},
  78.     {"letter",    612, 792},
  79.     {"legal",    612, 1008},
  80.     {"ledger",    1224, 792},
  81.     {"p11x17",    792, 1224}
  82. };
  83.  
  84. #define PAGESIZELIST    (sizeof(PageSizes)/sizeof(PageSizes[0]))
  85.  
  86. #ifdef A4
  87. int PageWidth  = 595;           /* page width A4 */
  88. int PageHeight = 842;           /* page height A4 */
  89. #else
  90. int PageWidth  = 612;           /* page width letter */
  91. int PageHeight = 792;           /* page height letter */
  92. #endif
  93.  
  94. static void 
  95. JPEGtoPS P2(imagedata *, JPEG, FILE *, PSfile) {
  96.   int llx, lly, urx, ury;        /* Bounding box coordinates */
  97.   size_t n;
  98.   float scale, sx, sy;           /* scale factors            */
  99.   time_t t;
  100.   int i;
  101.  
  102.   /* read image parameters and fill JPEG struct*/
  103.   if (!AnalyzeJPEG(JPEG)) {
  104.     fprintf(stderr, "Error: '%s' is not a proper JPEG file!\n", JPEG->filename);
  105.     return;
  106.   }
  107.  
  108.   if (!quiet)
  109.       fprintf(stderr, "Note on file '%s': %dx%d pixel, %d color component%s\n",
  110.     JPEG->filename, JPEG->width, JPEG->height, JPEG->components,
  111.     (JPEG->components == 1 ? "" : "s"));
  112.  
  113.   /* "Use resolution from file" was requested, but we couldn't find any */
  114.   if (JPEG->dpi == DPI_USE_FILE && !quiet) { 
  115.     fprintf(stderr,
  116.         "Note: no resolution values found in JPEG file - using standard scaling.\n");
  117.     JPEG->dpi = DPI_IGNORE;
  118.   }
  119.  
  120.   if (JPEG->dpi == DPI_IGNORE) {
  121.     if (JPEG->width > JPEG->height && autorotate) {    /* switch to landscape if needed */
  122.       JPEG->landscape = TRUE;
  123.       if (!quiet)
  124.       fprintf(stderr, 
  125.         "Note: image width exceeds height - producing landscape output!\n");
  126.     }
  127.     if (!JPEG->landscape) {       /* calculate scaling factors */
  128.       sx = (float) (PageWidth - 2*Margin) / JPEG->width;
  129.       sy = (float) (PageHeight - 2*Margin) / JPEG->height;
  130.     }else {
  131.       sx = (float) (PageHeight - 2*Margin) / JPEG->width;
  132.       sy = (float) (PageWidth - 2*Margin) / JPEG->height;
  133.     }
  134.     scale = min(sx, sy);    /* We use at least one edge of the page */
  135.   } else {
  136.     if (!quiet)
  137.     fprintf(stderr, "Note: Using resolution %d dpi.\n", (int) JPEG->dpi);
  138.     scale = 72 / JPEG->dpi;     /* use given image resolution */
  139.   }
  140.  
  141.   if (JPEG->landscape) {
  142.     /* landscape: move to (urx, lly) */
  143.     urx = PageWidth - Margin;
  144.     lly = Margin;
  145.     ury = (int) (Margin + scale*JPEG->width + 0.9);    /* ceiling */
  146.     llx = (int) (urx - scale * JPEG->height);          /* floor  */
  147.   }else {
  148.     /* portrait: move to (llx, lly) */
  149.     llx = lly = Margin;
  150.     urx = (int) (llx + scale * JPEG->width + 0.9);     /* ceiling */
  151.     ury = (int) (lly + scale * JPEG->height + 0.9);    /* ceiling */
  152.   }
  153.  
  154.   time(&t);
  155.  
  156.   /* produce EPS header comments */
  157.   fprintf(PSfile, "%%!PS-Adobe-3.0 EPSF-3.0\n");
  158.   fprintf(PSfile, "%%%%Creator: jpeg2ps %s by Thomas Merz\n", VERSION);
  159.   fprintf(PSfile, "%%%%Title: %s\n", JPEG->filename);
  160.   fprintf(PSfile, "%%%%CreationDate: %s", ctime(&t));
  161.   fprintf(PSfile, "%%%%BoundingBox: %d %d %d %d\n", 
  162.                    llx, lly, urx, ury);
  163.   fprintf(PSfile, "%%%%DocumentData: %s\n", 
  164.                   JPEG->mode == BINARY ? "Binary" : "Clean7Bit");
  165.   fprintf(PSfile, "%%%%LanguageLevel: 2\n");
  166.   fprintf(PSfile, "%%%%EndComments\n");
  167.   fprintf(PSfile, "%%%%BeginProlog\n");
  168.   fprintf(PSfile, "%%%%EndProlog\n");
  169.   fprintf(PSfile, "%%%%Page: 1 1\n");
  170.  
  171.   fprintf(PSfile, "/languagelevel where {pop languagelevel 2 lt}");
  172.   fprintf(PSfile, "{true} ifelse {\n");
  173.   fprintf(PSfile, "  (JPEG file '%s' needs PostScript Level 2!",
  174.                   JPEG->filename);
  175.   fprintf(PSfile, "\\n) dup print flush\n");
  176.   fprintf(PSfile, "  /Helvetica findfont 20 scalefont setfont ");
  177.   fprintf(PSfile, "100 100 moveto show showpage stop\n");
  178.   fprintf(PSfile, "} if\n");
  179.  
  180.   fprintf(PSfile, "save\n");
  181.   fprintf(PSfile, "/RawData currentfile ");
  182.  
  183.   if (JPEG->mode == ASCIIHEX)            /* hex representation... */
  184.     fprintf(PSfile, "/ASCIIHexDecode filter ");
  185.   else if (JPEG->mode == ASCII85)        /* ...or ASCII85         */
  186.     fprintf(PSfile, "/ASCII85Decode filter ");
  187.   /* else binary mode: don't use any additional filter! */
  188.  
  189.   fprintf(PSfile, "def\n");
  190.  
  191.   fprintf(PSfile, "/Data RawData << ");
  192.   fprintf(PSfile, ">> /DCTDecode filter def\n");
  193.  
  194.   /* translate to lower left corner of image */
  195.   fprintf(PSfile, "%d %d translate\n", (JPEG->landscape ? 
  196.                    PageWidth - Margin : Margin), Margin);
  197.  
  198.   if (JPEG->landscape)                 /* rotation for landscape */
  199.     fprintf(PSfile, "90 rotate\n");
  200.       
  201.   fprintf(PSfile, "%.2f %.2f scale\n", /* scaling */
  202.                    JPEG->width * scale, JPEG->height * scale);
  203.   fprintf(PSfile, "/Device%s setcolorspace\n", 
  204.                   ColorSpaceNames[JPEG->components]);
  205.   fprintf(PSfile, "{ << /ImageType 1\n");
  206.   fprintf(PSfile, "     /Width %d\n", JPEG->width);
  207.   fprintf(PSfile, "     /Height %d\n", JPEG->height);
  208.   fprintf(PSfile, "     /ImageMatrix [ %d 0 0 %d 0 %d ]\n",
  209.                   JPEG->width, -JPEG->height, JPEG->height);
  210.   fprintf(PSfile, "     /DataSource Data\n");
  211.   fprintf(PSfile, "     /BitsPerComponent %d\n", 
  212.                   JPEG->bits_per_component);
  213.  
  214.   /* workaround for color-inverted CMYK files produced by Adobe Photoshop:
  215.    * compensate for the color inversion in the PostScript code
  216.    */
  217.   if (JPEG->adobe && JPEG->components == 4) {
  218.     if (!quiet)
  219.     fprintf(stderr, "Note: Adobe-conforming CMYK file - applying workaround for color inversion.\n");
  220.     fprintf(PSfile, "     /Decode [1 0 1 0 1 0 1 0]\n");
  221.   }else {
  222.     fprintf(PSfile, "     /Decode [0 1");
  223.     for (i = 1; i < JPEG->components; i++) 
  224.       fprintf(PSfile," 0 1");
  225.     fprintf(PSfile, "]\n");
  226.   }
  227.  
  228.   fprintf(PSfile, "  >> image\n");
  229.   fprintf(PSfile, "  Data closefile\n");
  230.   fprintf(PSfile, "  RawData flushfile\n");
  231.   fprintf(PSfile, "  showpage\n");
  232.   fprintf(PSfile, "  restore\n");
  233.   fprintf(PSfile, "} exec");
  234.  
  235.   /* seek to start position of JPEG data */
  236.   fseek(JPEG->fp, JPEG->startpos, SEEK_SET);
  237.  
  238.   switch (JPEG->mode) {
  239.   case BINARY:
  240.     /* important: ONE blank and NO newline */
  241.     fprintf(PSfile, " ");
  242. #ifdef DOS
  243.     fflush(PSfile);               /* up to now we have CR/NL mapping */
  244.     setmode(fileno(PSfile), O_BINARY);    /* continue in binary mode */
  245. #endif
  246.     /* copy data without change */
  247.     while ((n = fread(buffer, 1, sizeof(buffer), JPEG->fp)) != 0)
  248.       fwrite(buffer, 1, n, PSfile);
  249. #ifdef DOS
  250.     fflush(PSfile);                      /* binary yet */
  251.     setmode(fileno(PSfile), O_TEXT);    /* text mode */
  252. #endif
  253.     break;
  254.  
  255.   case ASCII85:
  256.     fprintf(PSfile, "\n");
  257.  
  258.     /* ASCII85 representation of image data */
  259.     if (ASCII85Encode(JPEG->fp, PSfile)) {
  260.       fprintf(stderr, "Error: internal problems with ASCII85Encode!\n");
  261.       exit(1);
  262.     }
  263.     break;
  264.  
  265.   case ASCIIHEX:
  266.     /* hex representation of image data (useful for buggy dvips) */
  267.     ASCIIHexEncode(JPEG->fp, PSfile);
  268.     break;
  269.   }
  270.   fprintf(PSfile, "\n%%%%EOF\n");
  271. }
  272.  
  273. static
  274. void usage P0(void) {
  275.   fprintf(stderr, "jpeg2ps %s: convert JPEG files to PostScript Level 2.\n",
  276.            VERSION);
  277.   fprintf(stderr, "(C) Thomas Merz 1994-1999\n\n");
  278.   fprintf(stderr, "usage: jpeg2ps [options] jpegfile > epsfile\n");
  279.   fprintf(stderr, "-a        auto rotate: produce landscape output if width > height\n");
  280.   fprintf(stderr, "-b        binary mode: output 8 bit data (default: 7 bit with ASCII85)\n");
  281.   fprintf(stderr, "-h        hex mode: output 7 bit data in ASCIIHex encoding\n");
  282.   fprintf(stderr, "-o <name> output file name\n");
  283.   fprintf(stderr, "-p <size> page size name. Known names are:\n");
  284.   fprintf(stderr, "          a0, a1, a2, a3, a4, a5, a6, b5, letter, legal, ledger, p11x17\n");
  285.   fprintf(stderr, "-q        quiet mode: suppress all informational messages\n");
  286.   fprintf(stderr, "-r <dpi>  resolution value (dots per inch)\n");
  287.   fprintf(stderr, "          0 means use value given in file, if any (disables autorotate)\n");
  288.   exit(1);
  289. }
  290.  
  291. int
  292. main P2(int, argc, char **, argv) {
  293.   imagedata image;
  294.   FILE *outfile;
  295.  
  296. #ifdef MAC
  297.   int i, bufLength;
  298.   char *cp, outfilename[512];
  299. #else
  300.   int opt, pagesizeindex = -1;
  301. #endif
  302.  
  303.   image.filename = NULL;
  304.   image.mode     = ASCII85;
  305.   image.startpos = 0L;
  306.   image.landscape= FALSE;
  307.   image.dpi      = DPI_IGNORE;
  308.   image.adobe    = FALSE;
  309.  
  310.   outfile = stdout;
  311.  
  312.  if (argc == 1)
  313.     usage();
  314.  
  315. #ifndef MAC
  316.   while ((opt = getopt(argc, argv, "abho:p:qr:")) != -1)
  317.     switch (opt) {
  318.       case 'a':
  319.           autorotate = TRUE;
  320.           break;
  321.       case 'b':
  322.       image.mode = BINARY;
  323.       break;
  324.       case 'h':
  325.       image.mode = ASCIIHEX;
  326.       break;
  327.       case 'o':
  328.       outfile = fopen(optarg, "w");
  329.       if (outfile == NULL) {
  330.         fprintf(stderr, "Error: cannot open output file %s.\n", optarg);
  331.         exit(-2);
  332.       } 
  333.       break;
  334.       case 'p':
  335.       for(pagesizeindex=0; pagesizeindex < PAGESIZELIST; pagesizeindex++)
  336.         if (!strcmp((const char *) optarg, PageSizes[pagesizeindex].name)) {
  337.         PageHeight = PageSizes[pagesizeindex].height;
  338.         PageWidth = PageSizes[pagesizeindex].width;
  339.         break;
  340.         }
  341.       if (pagesizeindex == PAGESIZELIST) {    /* page size name not found */
  342.         fprintf(stderr, "Error: Unknown page size %s.\n", optarg);
  343.         exit(-3);
  344.       }
  345.       break;
  346.       case 'q':
  347.           quiet = TRUE;
  348.       break;
  349.       case 'r':
  350.       image.dpi = (float) atof(optarg);
  351.       if (image.dpi < 0) {
  352.         fprintf(stderr, "Error: bad resolution value %f !\n", image.dpi);
  353.         exit(1);
  354.       }
  355.       break;
  356.       case '?':
  357.       usage();
  358.     }
  359.  
  360.   if (pagesizeindex != -1 && ! quiet)    /* page size user option given */
  361.       fprintf(stderr, "Note: Using %s page size.\n",
  362.             PageSizes[pagesizeindex].name);
  363.  
  364.   if (optind == argc)    /* filename missing */
  365.     usage();
  366.   else
  367.     image.filename = argv[optind];
  368.  
  369.   if (!image.filename)
  370.     usage();
  371.  
  372.   if ((image.fp = fopen(image.filename, READMODE)) == NULL) {
  373.     fprintf(stderr, "Error: couldn't read JPEG file '%s'!\n", 
  374.       image.filename),
  375.     exit(1);
  376.   }
  377.  
  378.   JPEGtoPS(&image, outfile);      /* convert JPEG data */
  379.   fclose(image.fp);
  380.   fclose(outfile);
  381.  
  382. #else /* MAC */
  383.  
  384.  for (i = 1; i < argc; i++) {
  385.     image.filename = argv[i];
  386.  
  387.     strcpy(outfilename, image.filename);
  388.     bufLength = strlen(outfilename);
  389.     cp = outfilename;
  390.     if (bufLength > 3)
  391.     {
  392.     cp += (bufLength - 4);
  393.     /* strip .jpg from terminating string */
  394.     if (strcmp(cp, ".jpg") == 0 || strcmp(cp, ".JPG") == 0) 
  395.         outfilename[bufLength - 4] = '\0';         
  396.     }
  397.     
  398.     strcat(outfilename, ".eps");
  399.  
  400.      if ((image.fp = fopen(image.filename, READMODE)) == NULL) {
  401.     fprintf(stderr, "Error: couldn't read JPEG file '%s'!\n", 
  402.     image.filename),
  403.     exit(1);
  404.      }
  405.  
  406.     outfile = fopen(outfilename, WRITEMODE);
  407.  
  408.     JPEGtoPS(&image, outfile);      /* convert JPEG data */
  409.  
  410.     fclose(image.fp);
  411.     fclose(outfile);
  412.   }
  413.  
  414. #endif    /* not MAC */
  415.  
  416.   return 0;
  417. }
  418.